@yltrcc/vditor 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,773 +1,317 @@
1
- <p align="center">
2
- <img alt="Vditor" src="https://b3log.org/images/brand/vditor-128.png" />
1
+ # yl-vditor 技术架构文档
3
2
 
4
- <br>
5
- 易于使用的 Markdown 编辑器,为适配不同的应用场景而生
6
- <br><br>
7
- <a title="MIT" target="_blank" href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-orange.svg?style=flat-square"></a>
8
- <a title="npm bundle size" target="_blank" href="https://www.npmjs.com/package/vditor"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/vditor?style=flat-square&color=blueviolet"></a>
9
- <a title="Version" target="_blank" href="https://www.npmjs.com/package/vditor"><img src="https://img.shields.io/npm/v/vditor.svg?style=flat-square"></a><br>
10
- <a title="Downloads" target="_blank" href="https://www.npmjs.com/package/vditor"><img src="https://img.shields.io/npm/dt/vditor.svg?style=flat-square&color=97ca00"></a>
11
- <a title="jsdelivr" target="_blank" href="https://www.jsdelivr.com/package/npm/vditor"><img src="https://data.jsdelivr.com/v1/package/npm/vditor/badge"/></a>
12
- <a title="Hits" target="_blank" href="https://github.com/88250/hits"><img src="https://hits.b3log.org/Vanessa219/vditor.svg"></a> <br><br>
13
- <a title="GitHub Watchers" target="_blank" href="https://github.com/Vanessa219/vditor/watchers"><img src="https://img.shields.io/github/watchers/Vanessa219/vditor.svg?label=Watchers&style=social"></a>
14
- <a title="GitHub Stars" target="_blank" href="https://github.com/Vanessa219/vditor/stargazers"><img src="https://img.shields.io/github/stars/Vanessa219/vditor.svg?label=Stars&style=social"></a>
15
- <a title="GitHub Forks" target="_blank" href="https://github.com/Vanessa219/vditor/network/members"><img src="https://img.shields.io/github/forks/Vanessa219/vditor.svg?label=Forks&style=social"></a>
16
- <a title="Author GitHub Followers" target="_blank" href="https://github.com/vanessa219"><img src="https://img.shields.io/github/followers/vanessa219.svg?label=Followers&style=social"></a>
17
- </p>
3
+ TypeScript 实现的浏览器端 Markdown 编辑器。
18
4
 
19
- <p align="center">
20
- <a href="https://github.com/Vanessa219/vditor/blob/master/README_en_US.md">English</a> &nbsp;|&nbsp; <a href="https://b3log.org/vditor/demo/index.html">Demo</a>
21
- </p>
5
+ ---
22
6
 
23
- <p align="center">
24
- 🔥 欢迎观摩我们的另一个开源项目 <a href="https://github.com/siyuan-note/siyuan">思源笔记</a>
25
- <p>
7
+ ## 目录
26
8
 
27
- ## 💡 简介
9
+ - [项目概述](#项目概述)
10
+ - [核心目录结构](#核心目录结构)
11
+ - [三种编辑模式](#三种编辑模式)
12
+ - [主入口文件](#主入口文件)
13
+ - [核心模块详解](#核心模块详解)
14
+ - [渲染流程](#渲染流程)
15
+ - [扩展功能模块](#扩展功能模块)
16
+ - [开发环境](#开发环境)
28
17
 
29
- [Vditor](https://b3log.org/vditor) 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript 以及 Vue、React、Angular 和 Svelte 等框架。
18
+ ---
30
19
 
31
- 欢迎到 [Vditor 官方讨论区](https://ld246.com/tag/vditor)了解更多。同时也欢迎关注 B3log 开源社区微信公众号 `B3log开源`:
20
+ ## 项目概述
32
21
 
33
- ![b3logos.jpg](https://b3logfile.com/file/2020/08/b3logos-032af045.jpg)
22
+ yl-vditor 是一个基于 TypeScript 开发的浏览器端 Markdown 编辑器,支持三种编辑模式:WYSIWYG(所见即所得)、IR(即时渲染)、SV(分屏预览)。
34
23
 
35
- ## 🗺️ 背景
24
+ 核心特点:
25
+ - 使用 TypeScript 实现
26
+ - 基于 Lute 引擎进行 Markdown 解析
27
+ - 支持模块化扩展
28
+ - 支持多种框架集成
36
29
 
37
- 随着 Markdown 排版方式的普及,越来越多的应用开始集成 Markdown 编辑器。目前主流可集成的 Markdown 编辑器现状如下:
30
+ ---
38
31
 
39
- * 有的仅支持分屏预览,即编辑区和预览区分离
40
- * 有的同时支持所见即所得和分屏预览,但所见即所得模式下不能完整支持 Markdown 语法排版
41
- * 几乎没有类似 Typora 的即时渲染
32
+ ## 核心目录结构
42
33
 
43
- 而这三点恰好对应了三种应用场景:
44
-
45
- * 分屏预览:适配传统的 Markdown 使用场景,适合大屏下编辑排版
46
- * 所见即所得:对不熟悉 Markdown 的用户友好,熟悉 Markdown 的用户也可以无缝使用
47
- * 即时渲染:理论上这是最为优雅的 Markdown 编辑方式,让熟悉 Markdown 的用户能够更专注于内容创作
48
-
49
- 所以,一个能够**适配应用场景**的 Markdown 编辑器至关重要,它需要考虑到:
50
-
51
- * 传统 Markdown 用户的使用场景,提供分屏预览
52
- * 富文本编辑用户的使用场景,提供所见即所得
53
- * 高阶 Markdown 用户的使用场景,提供即时渲染
54
-
55
- Vditor 在这些方面做了努力,希望能为现代化的通用 Markdown 编辑领域做出一些贡献。
56
-
57
- ## ✨ 特性
58
-
59
- * 支持三种编辑模式:所见即所得(wysiwyg)、即时渲染(ir)、分屏预览(sv)
60
- * 支持大纲、数学公式、脑图、图表、流程图、甘特图、时序图、五线谱、[多媒体](https://ld246.com/article/1589813914768)、语音阅读、标题锚点、代码高亮及复制、graphviz 渲染、[plantuml](https://plantuml.com)UML图
61
- * 导出、图片懒加载、任务列表、多平台预览、多主题切换、复制到微信公众号/知乎功能
62
- * 实现 CommonMark 和 GFM 规范,可对 Markdown 进行格式化和语法树查看,并支持[10+项](https://ld246.com/article/1549638745630#options-preview-markdown)配置
63
- * 工具栏包含 36+ 项操作,除支持扩展外还可对每一项中的[快捷键](https://ld246.com/article/1582778815353)、提示、提示位置、图标、点击事件、类名、子工具栏进行自定义
64
- * 表情/at/话题等自动补全扩展
65
- * 可使用拖拽、剪切板粘贴上传,显示实时上传进度,支持 CORS 跨域上传
66
- * 实时保存内容,防止意外丢失
67
- * 录音支持,用户可直接发布语音
68
- * 粘贴 HTML 自动转换为 Markdown,如粘贴中包含外链图片可通过指定接口上传到服务器
69
- * 支持主窗口大小拖拽、字符计数
70
- * 多主题支持,内置黑白绿三套主题
71
- * 多语言支持,内置中、英、韩文本地化
72
- * 支持主流浏览器,对移动端友好
73
-
74
- ![editor.png](https://b3logfile.com/file/2020/07/editor-b304aa97.png)
75
-
76
- ![preview.png](https://b3logfile.com/file/2020/05/preview-80846f66.png)
77
-
78
- ## 🔮 编辑模式
79
-
80
- ### 所见即所得(WYSIWYG)
81
-
82
- *所见即所得*模式对不熟悉 Markdown 的用户较为友好,熟悉 Markdown 的话也可以无缝使用。
34
+ ```
35
+ yl-vditor/
36
+ ├── src/
37
+ │ ├── index.ts # 主入口,Vditor
38
+ │ ├── method.ts # 静态工具方法
39
+ │ ├── assets/ # 静态资源
40
+ │ │ ├── less/ # 样式文件
41
+ │ │ ├── images/ # 图片资源
42
+ │ │ └── js/ # 第三方库 (highlight, katex, mermaid, lute 等)
43
+ │ └── ts/ # TypeScript 源码
44
+ │ ├── constants.ts # 常量定义
45
+ │ ├── ir/ # IR 模式 (即时渲染模式)
46
+ │ ├── sv/ # SV 模式 (分屏预览模式)
47
+ │ ├── wysiwyg/ # WYSIWYG 模式 (所见即所得)
48
+ │ ├── toolbar/ # 工具栏
49
+ │ ├── markdown/ # Markdown 渲染相关
50
+ │ ├── preview/ # 预览相关
51
+ │ ├── hint/ # 提示补全
52
+ │ ├── upload/ # 文件上传
53
+ │ ├── undo/ # 撤销重做
54
+ │ ├── util/ # 工具函数
55
+ │ └── ui/ # UI 相关
56
+ └── package.json
57
+ ```
83
58
 
84
- ![vditor-wysiwyg](https://b3logfile.com/file/2020/07/wysiwyg-4f216b9b.gif)
59
+ ---
85
60
 
86
- ### 即时渲染(IR)
61
+ ## 三种编辑模式
87
62
 
88
- *即时渲染*模式对熟悉 Typora 的用户应该不会感到陌生,理论上这是最优雅的 Markdown 编辑方式。
63
+ | 模式 | 名称 | 目录 | 说明 |
64
+ |------|------|------|------|
65
+ | WYSIWYG | 所见即所得 | `src/ts/wysiwyg/` | 对不熟悉 Markdown 的用户友好 |
66
+ | IR | 即时渲染 | `src/ts/ir/` | 类似 Typora,理论最优雅 |
67
+ | SV | 分屏预览 | `src/ts/sv/` | 传统模式,左右分屏 |
89
68
 
90
- ![vditor-ir](https://b3logfile.com/file/2020/07/ir-67cd956c.gif)
69
+ ---
91
70
 
92
- ### 分屏预览(SV)
71
+ ## 主入口文件
93
72
 
94
- 传统的*分屏预览*模式适合大屏下的 Markdown 编辑。
73
+ ### src/index.ts
95
74
 
96
- ![vditor-sv](https://b3logfile.com/file/2020/07/sv-595dcb28.gif)
75
+ `Vditor` 类是整个编辑器的主入口,在 `init()` 方法中初始化所有组件:
97
76
 
98
- ## 🍱 语法支持
77
+ ```typescript
78
+ class Vditor {
79
+ constructor(id: string | HTMLElement, options?: IOptions)
80
+
81
+ init() {
82
+ // 初始化各模块
83
+ this.vditor.lute = new Lute(...)
84
+ this.vditor.sv = new SV(this.vditor)
85
+ this.vditor.wysiwyg = new WYSIWYG(this.vditor)
86
+ this.vditor.ir = new IR(this.vditor)
87
+ this.vditor.toolbar = new Toolbar(this.vditor)
88
+ this.vditor.preview = new Preview(this.vditor)
89
+ this.vditor.hint = new Hint(this.vditor)
90
+ this.vditor.undo = new Undo(this.vditor)
91
+ this.vditor.upload = new Upload(this.vditor)
92
+ }
93
+ }
94
+ ```
99
95
 
100
- * 所有 CommonMark 语法:分隔线、ATX 标题、Setext 标题、缩进代码块、围栏代码块、HTML 块、链接引用定义、段落、块引用、列表、反斜杠转义、HTML 实体、行级代码、强调、加粗、链接、图片、行级 HTML、硬换行、软换行和纯文本。
101
- * 所有 GFM 语法:表格、任务列表项、删除线、自动链接、XSS 过滤
102
- * 常用 Markdown 扩展语法:脚注、ToC、自定义标题 ID
103
- * 图表语法
104
- * 流程图、时序图、甘特图,通过 Mermaid 支持
105
- * Graphviz
106
- * 折线图、饼图、脑图等,通过 ECharts 支持
107
- * 五线谱:通过 abc.js 支持
108
- * 数学公式:数学公式块、行级数学公式,通过 MathJax 和 KaTeX 支持
109
- * YAML Front Matter
110
- * 中文语境优化
111
- * 中西文之间插入空格
112
- * 术语拼写修正
113
- * 中文后跟英文逗号句号等标点替换为中文对应标点
96
+ ### src/method.ts
114
97
 
115
- 以上大部分特性可以通过开关配置是否启用,开发者可根据自己的应用场景选择搭配。
98
+ 静态工具方法集合,包含:
99
+ - `md2html()`: Markdown 转 HTML
100
+ - `preview()`: 页面 Markdown 渲染
101
+ - `mermaidRender()`: 流程图渲染
102
+ - `mathRender()`: 数学公式渲染
103
+ - `codeRender()`: 代码块渲染
104
+ - 等等...
116
105
 
117
- ## 🗃 案例
106
+ ---
118
107
 
119
- * [Sym](https://github.com/88250/symphony) 一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)平台
120
- * [Solo](https://github.com/88250/solo) & [Pipe](https://github.com/88250/pipe) B3log 分布式社区的博客端节点,欢迎加入下一代社区网络
121
- * [Tditor](https://tditor.com) 基于React、Vditor、Springboot,一款打造极致文字创作体验的在线Markdown编辑平台
122
- * [Arya](https://github.com/nicejade/markdown-online-editor) 基于 Vue、Vditor,所构建的在线 Markdown 编辑器
123
- * [更多案例](https://github.com/Vanessa219/vditor/network/dependents?package_id=UGFja2FnZS0zMTY2Mzg4MzE%3D)
108
+ ## 核心模块详解
124
109
 
125
- ## 🛠️ 使用文档
110
+ ### 1. WYSIWYG 模式 (`src/ts/wysiwyg/`)
126
111
 
127
- ### CommonJS
112
+ | 文件 | 功能 |
113
+ |------|------|
114
+ | `index.ts` | 主类,绑定事件(复制/剪切/粘贴/拖拽等) |
115
+ | `input.ts` | 输入处理,调用 SpinVditorDOM 渲染 |
116
+ | `renderDomByMd.ts` | Markdown 渲染 + 图片尺寸处理 + 文档链接处理 |
117
+ | `afterRenderEvent.ts` | 渲染后事件处理 |
118
+ | `keydown.ts` | 键盘事件处理 |
119
+ | `paste.ts` | 粘贴事件处理 |
120
+ | `cut.ts` | 剪切事件处理 |
121
+ | `drop.ts` | 拖放事件处理 |
128
122
 
129
- * 安装依赖
123
+ ### 2. IR 模式 (`src/ts/ir/`)
130
124
 
131
- ```shell
132
- npm install vditor --save
133
- ```
125
+ | 文件 | 功能 |
126
+ |------|------|
127
+ | `index.ts` | 主类,初始化 IR 编辑器 |
128
+ | `input.ts` | 输入处理 |
129
+ | `keydown.ts` | 键盘事件处理 |
130
+ | `paste.ts` | 粘贴事件处理 |
134
131
 
135
- * 在代码中引入并初始化对象,可参考 [index.js](https://github.com/Vanessa219/vditor/blob/master/demo/index.js)
132
+ ### 3. SV 模式 (`src/ts/sv/`)
136
133
 
137
- ```ts
138
- import Vditor from 'vditor'
139
- import "~vditor/src/assets/less/index"
134
+ | 文件 | 功能 |
135
+ |------|------|
136
+ | `index.ts` | 主类,初始化 SV 编辑器 |
137
+ | `input.ts` | 输入处理 |
138
+ | `keydown.ts` | 键盘事件处理 |
140
139
 
141
- const vditor = new Vditor(id, {options...})
142
- ```
140
+ ### 4. 工具栏模块 (`src/ts/toolbar/`)
143
141
 
144
- ### HTML script
142
+ | 文件 | 功能 |
143
+ |------|------|
144
+ | `index.ts` | 主类,生成工具栏 |
145
+ | `MenuItem.ts` | 菜单项基类 |
146
+ | `items/` | 各菜单项实现 |
145
147
 
146
- * HTML 中插入 CSS 和 JavaScript,可参考 [demo](https://b3log.org/vditor/demo/index.html)
148
+ 内置 36+ 个菜单项,包括:
149
+ - `Bold`: 粗体
150
+ - `Italic`: 斜体
151
+ - `Headings`: 标题
152
+ - `Emoji`: 表情
153
+ - `Upload`: 上传
154
+ - `Record`: 录音
155
+ - 等等...
147
156
 
148
- ```html
149
- <!-- ⚠️生产环境请指定版本号,如 https://unpkg.com/vditor@x.x.x/dist... -->
150
- <link rel="stylesheet" href="https://unpkg.com/vditor/dist/index.css" />
151
- <script src="https://unpkg.com/vditor/dist/index.min.js"></script>
152
- ```
157
+ ### 5. Markdown 模块 (`src/ts/markdown/`)
153
158
 
154
- ### 示例代码
155
-
156
- * [官方示例](https://b3log.org/vditor/demo/index.html) / [示例源码](https://github.com/Vanessa219/b3log-index/tree/master/src/vditor)
157
- * [CommonJS Editor](https://github.com/Vanessa219/vditor/blob/master/demo/index.js)
158
- * [CommonJS Render](https://github.com/Vanessa219/vditor/blob/master/demo/render.js)
159
- * [在Svelte中使用](https://github.com/HerbertHe/svelte-vditor-demo)
160
-
161
- ### 主题
162
-
163
- #### 编辑器主题
164
-
165
- 编辑器所展现的外观。内置classic,dark 2 套主题。
166
-
167
- * 编辑器初始化时可通过 `options.theme` 设置内置主题
168
- * 初始化完成后可通过 `setTheme` 更新编辑器主题
169
- * 可通过修改 [index.less](https://github.com/Vanessa219/vditor/blob/master/src/assets/less/index.less) 中的变量对主题颜色进行定制
170
- * 可参考现有结构和类名在原有基础上进行修改
171
-
172
- #### 内容主题
173
-
174
- Markdown 输出的 HTML 所展现的外观。内置 ant-design, light,dark,wechat 4 套主题。支持内容主题扩展接口。
175
-
176
- * 需在显示元素上添加 `class="vditor-reset"`
177
- * 编辑器初始化时可通过 `options.preview.theme` 设置内置或自己开发的主题列表
178
- * 内容渲染初始化时可通过 `IPreviewOptions.theme` 设置内置或自己开发的主题
179
- * 初始化完成后可通过 `setTheme` 或 `setContentTheme` 更新内容主题
180
-
181
- #### 代码主题
182
-
183
- 代码块所展现的外观。内置 github 等 36 套主题。
184
-
185
- * 编辑器初始化时可通过 `options.preview.hljs` 对代码块样式、行号、是否启用进行设置
186
- * 内容渲染初始化时可通过 `IPreviewOptions.hljs` 对代码块样式、行号、是否启用进行设置
187
- * 初始化完成后可通过 `setTheme` 或 `setCodeTheme` 更新代码主题
188
-
189
- ### API
190
-
191
- #### id
192
-
193
- 可填入元素 `id` 或元素自身 `HTMLElement`
194
-
195
- ⚠️:当填入元素自身的 `HTMLElement` 时需设置 `options.cache.id` 或将 `options.cache.enable` 设置为 `false`
196
-
197
- #### options
198
-
199
- | | 说明 | 默认值 |
200
- | - | - | - |
201
- | i18n | 多语言,参见 ITips | - |
202
- | undoDelay | 历史记录间隔 | - |
203
- | after | 编辑器异步渲染完成后的回调方法 | - |
204
- | height | 编辑器总高度 | 'auto' |
205
- | minHeight | 编辑区域最小高度 | - |
206
- | width | 编辑器总宽度,支持 % | 'auto' |
207
- | placeholder | 输入区域为空时的提示 | '' |
208
- | lang | 语言种类:de_DE, en_US, es_ES, fr_FR, ja_JP, ko_KR, pt_BR, ru_RU, sv_SE, vi_VN, zh_CN, zh_TW | 'zh_CN' |
209
- | input(value: string) | 输入后触发 | - |
210
- | focus(value: string) | 聚焦后触发 | - |
211
- | blur(value: string) | 失焦后触发 | - |
212
- | keydown(event: KeyboardEvent) | 按下后触发 | - |
213
- | esc(value: string) | <kbd>esc</kbd> 按下后触发 | - |
214
- | ctrlEnter(value: string) | <kbd>⌘/ctrl+enter</kbd> 按下后触发 | - |
215
- | select(value: string) | 编辑器中选中文字后触发 | - |
216
- | unSelect() | 编辑器中未选中文字后触发 | - |
217
- | tab | <kbd>tab</kbd> 键操作字符串,支持 `\t` 及任意字符串 | - |
218
- | typewriterMode | 是否启用打字机模式 | false |
219
- | cdn | 配置自建 CDN 地址 | `https://unpkg.com/vditor@${VDITOR_VERSION}` |
220
- | mode | 可选模式:sv, ir, wysiwyg | 'ir' |
221
- | debugger | 是否显示日志 | false |
222
- | value | 编辑器初始化值 | '' |
223
- | theme | 主题:classic, dark | 'classic' |
224
- | icon | 图标风格:ant, material | 'ant' |
225
- | customRenders: {language: string, render: (element: HTMLElement, vditor: IVditor) => void}[] | 自定义渲染器 | [] |
226
- | customWysiwygToolbar(type: TWYSISYGToolbar, element: HTMLElement): void | 对 wysiwyg 模式下的工具栏进行自定义 | - |
227
-
228
- #### options.toolbar
229
-
230
- * 工具栏,可使用 name 进行简写: `toolbar: ['emoji', 'br', 'bold', '|', 'line']` 。默认值参见 [src/ts/util/Options.ts](https://github.com/Vanessa219/vditor/blob/master/src/ts/util/Options.ts)
231
- * name 可枚举为: `emoji`,`headings`,`bold`,`italic`,`strike`,`|`,`line`,`quote`,`list`,`ordered-list`,`check` ,`outdent` ,`indent`,`code`,`inline-code`,`insert-after`,`insert-before` ,`undo`,`redo`,`upload`,`link`,`table`,`record`,`edit-mode`,`both`,`preview`,`fullscreen`,`outline`,`code-theme`,`content-theme`,`export`, `devtools`,`info`,`help`,`br`
232
- * 当 `name` 不在枚举中时,可以添加自定义按钮,格式如下:
233
-
234
- ```js
235
- new Vditor('vditor', {
236
- toolbar: [
237
- {
238
- hotkey: '⇧⌘S',
239
- name: 'sponsor',
240
- tipPosition: 's',
241
- tip: '成为赞助者',
242
- className: 'right',
243
- icon: '<svg t="1589994565028" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2808" width="32" height="32"><path d="M506.6 423.6m-29.8 0a29.8 29.8 0 1 0 59.6 0 29.8 29.8 0 1 0-59.6 0Z" fill="#0F0F0F" p-id="2809"></path><path d="M717.8 114.5c-83.5 0-158.4 65.4-211.2 122-52.7-56.6-127.7-122-211.2-122-159.5 0-273.9 129.3-273.9 288.9C21.5 562.9 429.3 913 506.6 913s485.1-350.1 485.1-509.7c0.1-159.5-114.4-288.8-273.9-288.8z" fill="#FAFCFB" p-id="2810"></path><path d="M506.6 926c-22 0-61-20.1-116-59.6-51.5-37-109.9-86.4-164.6-139-65.4-63-217.5-220.6-217.5-324 0-81.4 28.6-157.1 80.6-213.1 53.2-57.2 126.4-88.8 206.3-88.8 40 0 81.8 14.1 124.2 41.9 28.1 18.4 56.6 42.8 86.9 74.2 30.3-31.5 58.9-55.8 86.9-74.2 42.5-27.8 84.3-41.9 124.2-41.9 79.9 0 153.2 31.5 206.3 88.8 52 56 80.6 131.7 80.6 213.1 0 103.4-152.1 261-217.5 324-54.6 52.6-113.1 102-164.6 139-54.8 39.5-93.8 59.6-115.8 59.6zM295.4 127.5c-72.6 0-139.1 28.6-187.3 80.4-47.5 51.2-73.7 120.6-73.7 195.4 0 64.8 78.3 178.9 209.6 305.3 53.8 51.8 111.2 100.3 161.7 136.6 56.1 40.4 88.9 54.8 100.9 54.8s44.7-14.4 100.9-54.8c50.5-36.3 108-84.9 161.7-136.6 131.2-126.4 209.6-240.5 209.6-305.3 0-74.9-26.2-144.2-73.7-195.4-48.2-51.9-114.7-80.4-187.3-80.4-61.8 0-127.8 38.5-201.7 117.9-2.5 2.6-5.9 4.1-9.5 4.1s-7.1-1.5-9.5-4.1C423.2 166 357.2 127.5 295.4 127.5z" fill="#141414" p-id="2811"></path><path d="M353.9 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2812"></path><path d="M659.3 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2813"></path><path d="M411.6 538.5c0 52.3 42.8 95 95 95 52.3 0 95-42.8 95-95v-31.7h-190v31.7z" fill="#5B5143" p-id="2814"></path><path d="M506.6 646.5c-59.6 0-108-48.5-108-108v-31.7c0-7.2 5.8-13 13-13h190.1c7.2 0 13 5.8 13 13v31.7c0 59.5-48.5 108-108.1 108z m-82-126.7v18.7c0 45.2 36.8 82 82 82s82-36.8 82-82v-18.7h-164z" fill="#141414" p-id="2815"></path><path d="M450.4 578.9a54.7 27.5 0 1 0 109.4 0 54.7 27.5 0 1 0-109.4 0Z" fill="#EA64F9" p-id="2816"></path><path d="M256 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2817"></path><path d="M703.3 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2818"></path></svg>',
244
- click () {alert('捐赠地址:https://ld246.com/sponsor')},
245
- }],
246
- })
247
- ```
159
+ | 文件 | 功能 |
160
+ |------|------|
161
+ | `setLute.ts` | Lute 引擎配置 |
162
+ | `getMarkdown.ts` | 获取 Markdown 内容 |
163
+ | `export.ts` | 导出功能 |
248
164
 
249
- | | 说明 | 默认值 |
250
- | - | - | - |
251
- | name | 唯一标示 | - |
252
- | icon | svg 图标 | - |
253
- | tip | 提示 | - |
254
- | tipPosition | 提示位置:'n', 'ne', 'nw', 's', 'se', 'sw', 'w', 'e' | - |
255
- | hotkey | 快捷键,格式为<kbd>⇧⌘</kbd>/<kbd>⌘</kbd>/<kbd>⌥⌘</kbd>| - |
256
- | suffix | 插入编辑器中的后缀 | - |
257
- | prefix | 插入编辑器中的前缀 | - |
258
- | click(event: Event, vditor: IVditor) | 自定义按钮点击时触发的事件 | - |
259
- | className | 样式名 | '' |
260
- | toolbar?: Array<options.toolbar> | 子菜单 | - |
261
-
262
- #### options.toolbarConfig
263
-
264
- | | 说明 | 默认值 |
265
- | - | - | - |
266
- | hide | 是否隐藏工具栏 | false |
267
- | pin | 是否固定工具栏 | false |
268
-
269
- #### options.counter
270
-
271
- | | 说明 | 默认值 |
272
- | - | - | - |
273
- | enable | 是否启用计数器 | false |
274
- | after(length: number, counter: options.counter): void | 字数统计回调 | - |
275
- | max | 允许输入的最大值 | - |
276
- | type | 统计类型:'markdown', 'text' | 'markdown' |
277
-
278
- #### options.cache
279
-
280
- | | 说明 | 默认值 |
281
- | - | - | - |
282
- | enable | 是否使用 localStorage 进行缓存 | true |
283
- | id | 缓存 key,第一个参数为元素且启用缓存时**必填** | - |
284
- | after(html: string): string | 缓存后的回调 | - |
285
-
286
- #### options.comment
287
-
288
- ⚠️:仅支持 wysiwyg 模式
289
-
290
- | | 说明 | 默认值 |
291
- | - | - | - |
292
- | enable | 是否启用评论模式 | false |
293
- | add(id: string, text: string, commentsData: ICommentsData[]) | 添加评论回调 | - |
294
- | remove(ids: string[]) | 删除评论回调 | - |
295
- | scroll(top: number) | 滚动回调 | - |
296
- | adjustTop(commentsData: ICommentsData[]) | 文档修改时,适配评论高度 | - |
297
-
298
- #### options.preview
299
-
300
- | | 说明 | 默认值 |
301
- | - | - | - |
302
- | delay | 预览 debounce 毫秒间隔 | 1000 |
303
- | maxWidth | 预览区域最大宽度 | 800 |
304
- | mode | 显示模式:both, editor | 'both' |
305
- | url | md 解析请求 | - |
306
- | parse(element: HTMLElement) | 预览回调 | - |
307
- | transform(html: string): string | 渲染之前回调 | - |
308
-
309
- #### options.preview.hljs
310
-
311
- | | 说明 | 默认值 |
312
- | - | - | - |
313
- | defaultLang | 未指定语言时默认使用该语言 | '' |
314
- | enable | 是否启用代码高亮 | true |
315
- | style | 可选值参见[Chroma](https://xyproto.github.io/splash/docs/longer/all.html) | `github` |
316
- | lineNumber | 是否启用行号 | false |
317
- | langs | 自定义指定语言 | [CODE_LANGUAGES](https://github.com/Vanessa219/vditor/blob/53ca8f9a0e511b37b5dae7c6b15eb933e9e02ccd/src/ts/constants.ts#L20) |
318
- | renderMenu(code: HTMLElement, copy: HTMLElement) | 渲染菜单按钮 | - |
319
-
320
- #### options.preview.markdown
321
-
322
- | | 说明 | 默认值 |
323
- | - | - | - |
324
- | autoSpace | 自动空格 | false |
325
- | gfmAutoLink | 自动链接 | true |
326
- | fixTermTypo | 自动矫正术语 | false |
327
- | toc | 插入目录 | false |
328
- | footnotes | 脚注 | true |
329
- | codeBlockPreview | wysiwyg 和 ir 模式下是否对代码块进行渲染 | true |
330
- | mathBlockPreview | wysiwyg 和 ir 模式下是否对数学公式进行渲染 | true |
331
- | paragraphBeginningSpace | 段落开头空两个 | false |
332
- | sanitize | 是否启用过滤 XSS | true |
333
- | listStyle | 为列表添加 data-style 属性 | false |
334
- | linkBase | 链接相对路径前缀 | '' |
335
- | linkPrefix | 链接强制前缀 | '' |
336
- | mark | 启用 mark 标记 | false |
337
- | sup | 上标 | false |
338
- | sub | 下标 | false |
339
-
340
- #### options.preview.theme
341
-
342
- | | 说明 | 默认值 |
343
- | - | - | - |
344
- | current | 当前主题 | "light" |
345
- | list | 可选主题列表 | { "ant-design": "Ant Design", dark: "Dark", light: "Light", wechat: "WeChat" } |
346
- | path | 主题样式地址 | `https://unpkg.com/vditor@${VDITOR_VERSION}/dist/css/content-theme` |
347
-
348
- #### options.preview.math
349
-
350
- | | 说明 | 默认值 |
351
- | - | - | - |
352
- | inlineDigit | 内联数学公式起始 $ 后是否允许数字 | false |
353
- | macros | 使用 MathJax 渲染时传入的宏定义 | {} |
354
- | engine | 数学公式渲染引擎:KaTeX, MathJax | 'KaTeX' |
355
- | mathJaxOptions | 数学公式渲染引擎为 MathJax 时的参数 | - |
356
-
357
- #### options.preview.actions?: Array<IPreviewAction | IPreviewActionCustom>
358
-
359
- 默认值为 ["desktop", "tablet", "mobile", "mp-wechat", "zhihu"]。
360
- 可从默认值中挑选进行配置,也可使用以下字段进行自定制开发。
361
-
362
- | | 说明 | 默认值 |
363
- | - | - | - |
364
- | key | 按钮唯一标识,不能为空 | - |
365
- | text | 按钮文字 | - |
366
- | tooltip | 提示 | - |
367
- | className | 按钮类名 | - |
368
- | click(key: string) | 按钮点击回调事件 | - |
369
-
370
- #### options.preview.render.media
371
-
372
- | | 说明 | 默认值 |
373
- |--------|-----------|------|
374
- | enable | 是否启用多媒体渲染 | true |
375
-
376
- #### options.image
377
-
378
- | | 说明 | 默认值 |
379
- | - | - | - |
380
- | isPreview | 是否预览图片 | true |
381
- | preview(bom: Element) => void | 图片预览处理 | - |
382
-
383
- #### options.link
384
-
385
- | | 说明 | 默认值 |
386
- | - | - | - |
387
- | isOpen | 是否打开链接地址 | true |
388
- | click(bom: Element) => void | 点击链接事件 | - |
389
-
390
- #### options.hint
391
-
392
- | | 说明 | 默认值 |
393
- | - | - | - |
394
- | parse | 是否进行 md 解析 | true |
395
- | delay | 提示 debounce 毫秒间隔 | 200 |
396
- | emoji | 默认表情,可从[lute/emoji_map](https://github.com/88250/lute/blob/master/parse/emoji_map.go) 中选取,也可自定义 | { '+1': '👍', '-1': '👎', 'heart': '❤️', 'cold_sweat': '😰' } |
397
- | emojiTail | 常用表情提示 | - |
398
- | emojiPath | 表情图片地址 | `https://unpkg.com/vditor@${VDITOR_VERSION}/dist/images/emoji` |
399
- | extend: IHintExtend[] | 对 @/话题等关键字自动补全的扩展 | [] |
400
-
401
- ```ts
402
- interface IHintData {
403
- html: string;
404
- value: string;
405
- }
165
+ 基于 Lute 引擎,支持:
166
+ - CommonMark 规范
167
+ - GFM 规范
168
+ - 数学公式
169
+ - 图表
170
+ - 脑图
171
+ - 等等...
406
172
 
407
- interface IHintExtend {
408
- key: string;
173
+ ### 6. 工具函数模块 (`src/ts/util/`)
409
174
 
410
- hint?(value: string): IHintData[] | Promise<IHintData[]>;
411
- }
412
- ```
175
+ | 文件 | 功能 |
176
+ |------|------|
177
+ | `Options.ts` | 配置选项合并与默认值 |
178
+ | `selection.ts` | 光标/选区操作 |
179
+ | `hasClosest.ts` | DOM 节点查找 |
180
+ | `imageResize.ts` | 图片拖拽调整尺寸 |
181
+ | `editorCommonEvent.ts` | 编辑器通用事件(复制/剪切/粘贴/拖拽等) |
182
+ | `fixBrowserBehavior.ts` | 浏览器行为修复 |
183
+ | `processCode.ts` | 代码块渲染处理 |
413
184
 
414
- #### options.upload
415
-
416
- * 文件上传的数据结构如下。后端返回的数据结构不一致时,可使用 `format` 进行转换。
417
-
418
- ```js
419
- // POST data
420
- xhr.send(formData); // formData = FormData.append("file[]", File)
421
- // return data
422
- {
423
- "msg": "",
424
- "code": 0,
425
- "data": {
426
- "errFiles": ['filename', 'filename2'],
427
- "succMap": {
428
- "filename3": "filepath3",
429
- "filename3": "filepath3"
430
- }
431
- }
432
- }
433
- ```
185
+ ---
434
186
 
435
- * 为了防止站外图片失效,`linkToImgUrl` 可将剪贴板中的站外图片地址传到服务器端进行保存处理,其数据结构如下:
436
-
437
- ```js
438
- // POST data
439
- xhr.send(JSON.stringify({url: src})); // src 为站外图片地址
440
- // return data
441
- {
442
- msg: '',
443
- code: 0,
444
- data : {
445
- originalURL: '',
446
- url: ''
447
- }
448
- }
449
- ```
187
+ ## 渲染流程
450
188
 
451
- * `success`,`format`,`error` 不会同时触发,具体调用情况如下:
452
-
453
- ```js
454
- if (xhr.status === 200) {
455
- if (vditor.options.upload.success) {
456
- vditor.options.upload.success(editorElement, xhr.responseText);
457
- } else {
458
- let responseText = xhr.responseText;
459
- if (vditor.options.upload.format) {
460
- responseText = vditor.options.upload.format(files as File [], xhr.responseText);
461
- }
462
- genUploadedLabel(responseText, vditor);
463
- }
464
- } else {
465
- if (vditor.options.upload.error) {
466
- vditor.options.upload.error(xhr.responseText);
467
- } else {
468
- vditor.tip.show(xhr.responseText);
469
- }
470
- }
471
- ```
189
+ ### WYSIWYG 模式渲染流程
472
190
 
473
- | | 说明 | 默认值 |
474
- | - | - | - |
475
- | xhr | 上传时使用的 XMLHttpRequest | - |
476
- | url | 上传 url,为空则不会触发上传相关事件 | '' |
477
- | max | 上传文件最大 Byte | 10 * 1024 * 1024 |
478
- | linkToImgUrl | 剪切板中包含图片地址时,使用此 url 重新上传 | '' |
479
- | linkToImgCallback(responseText: string) | 图片地址上传回调 | - |
480
- | linkToImgFormat(responseText: string): string | 对图片地址上传的返回值进行格式化 | - |
481
- | success(editor: HTMLPreElement, msg: string) | 上传成功回调 | - |
482
- | error(msg: string) | 上传失败回调 | - |
483
- | token | CORS 上传验证,头为 X-Upload-Token | - |
484
- | withCredentials | 跨站点访问控制 | false |
485
- | headers | 请求头设置 | - |
486
- | filename(name: string): string | 文件名安全处理 | name => name.replace(/\W/g, '') |
487
- | accept | 文件上传类型,同[input accept](https://www.w3schools.com/tags/att_input_accept.asp) | - |
488
- | validate(files: File[]) => string \| boolean | 校验,成功时返回 true 否则返回错误信息 | - |
489
- | handler(files: File[]) => string \| null \| Promise<string> \| Promise<null> | 自定义上传,当发生错误时返回错误信息 | - |
490
- | format(files: File[], responseText: string): string | 对服务端返回的数据进行转换,以满足内置的数据结构 | - |
491
- | file(files: File[]): File[] \| Promise<File[]> | 将上传的文件处理后再返回 | - |
492
- | cancel(files: File[]): void | 取消正在上传的文件 | - |
493
- | setHeaders(): { [key: string]: string } | 上传前使用返回值设置头 | - |
494
- | extraData: { [key: string]: string \| Blob } | 为 FormData 添加额外的参数 | - |
495
- | multiple | 上传文件是否为多个 | true |
496
- | fieldName | 上传字段名称 | 'file[]' |
497
- | renderLinkDest?(vditor: IVditor, node: ILuteNode, entering: boolean): [string, number] | 处理剪贴板中的图片地址 | '' |
498
-
499
- #### options.resize
500
-
501
- | | 说明 | 默认值 |
502
- | - | - | - |
503
- | enable | 是否支持大小拖拽 | false |
504
- | position | 拖拽栏位置:'top', 'bottom' | 'bottom' |
505
- | after(height: number) | 拖拽结束的回调 | - |
506
-
507
- #### options.classes
508
-
509
- | | 说明 | 默认值 |
510
- | - | - | - |
511
- | preview | 预览元素上的 className | '' |
512
-
513
- #### options.fullscreen
514
-
515
- | | 说明 | 默认值 |
516
- | - | - | - |
517
- | index | 全屏层级 | 90 |
518
-
519
- #### options.outline
520
-
521
- | | 说明 | 默认值 |
522
- | - | - | - |
523
- | enable | 初始化是否展现大纲 | false |
524
- | position | 大纲位置:'left', 'right' | 'left' |
525
-
526
- #### methods
527
-
528
- | | 说明 |
529
- | - | - |
530
- | exportJSON(markdown: string) | 根据 Markdown 获取对应 JSON |
531
- | getValue() | 获取 Markdown 内容 |
532
- | getHTML() | 获取 HTML 内容 |
533
- | insertValue(value: string, render = true) | 在焦点处插入内容,并默认进行 Markdown 渲染 |
534
- | focus() | 聚焦到编辑器 |
535
- | blur() | 让编辑器失焦 |
536
- | disabled() | 禁用编辑器 |
537
- | enable() | 解除编辑器禁用 |
538
- | getSelection(): string | 返回选中的字符串 |
539
- | setValue(markdown: string, clearStack = false) | 设置编辑器内容且选中清空历史栈 |
540
- | clearStack() | 清空撤销和重做记录栈|
541
- | renderPreview(value?: string) | 设置预览区域内容 |
542
- | getCursorPosition():{top: number, left: number} | 获取焦点位置 |
543
- | deleteValue() | 删除选中内容 |
544
- | updateValue(value: string) | 更新选中内容 |
545
- | isUploading() | 上传是否还在进行中 |
546
- | clearCache() | 清除缓存 |
547
- | disabledCache() | 禁用缓存 |
548
- | enableCache() | 启用缓存 |
549
- | html2md(value: string) | HTML 转 md |
550
- | tip(text: string, time: number) | 消息提示。time 为 0 将一直显示 |
551
- | setPreviewMode(mode: "both" \| "editor") | 设置预览模式 |
552
- | setTheme(theme: "dark" \| "classic", contentTheme?: string, codeTheme?: string, contentThemePath?: string) | 设置主题、内容主题及代码块风格 |
553
- | getCurrentMode(): string | 获取编辑器当前编辑模式 |
554
- | destroy() | 销毁编辑器 |
555
- | getCommentIds(): {id: string, top: number}[] | 获取所有评论 |
556
- | hlCommentIds(ids: string[]) | 高亮评论 |
557
- | unHlCommentIds(ids: string[]) | 取消评论高亮 |
558
- | removeCommentIds(removeIds: string[]) | 删除评论 |
559
- | updateToolbarConfig(config: {hide?: boolean, pin?: boolean}) | 更新工具栏配置 |
560
- | insertEmptyBlock(position: InsertPosition) | 插入空快 |
561
-
562
- #### static methods
563
-
564
- * 不需要进行编辑操作时,仅需引入 [`method.min.js`](https://unpkg.com/vditor/dist/) 后如下直接调用
565
-
566
- ```js
567
- Vditor.mermaidRender(document)
568
191
  ```
569
-
570
- ```js
571
- import VditorPreview from 'vditor/dist/method.min'
572
- VditorPreview.mermaidRender(document)
192
+ 用户输入
193
+
194
+ input.ts (keydown/paste/cut/drop)
195
+
196
+ getMarkdown.ts (获取当前 Markdown)
197
+
198
+ Lute 引擎 (Markdown → HTML)
199
+
200
+ renderDomByMd.ts (SpinVditorDOM)
201
+ ├─ preprocessImageSize() (图片尺寸预处理)
202
+ ├─ processImageSizeInDOM() (图片尺寸后处理)
203
+ └─ processDocLinkInWYSIWYG() (文档链接处理)
204
+
205
+ afterRenderEvent.ts (渲染后事件)
206
+
207
+ undo.ts (保存撤销栈)
208
+
209
+ cache.ts (本地缓存)
573
210
  ```
574
211
 
575
- * 需要对页面中的 Markdown 进行渲染时可直接调用 `preview` 方法,参数如下:
576
-
577
- ```ts
578
- previewElement: HTMLDivElement, // 使用该元素进行渲染
579
- markdown: string, // 需要渲染的 markdown 原文
580
- options?: IPreviewOptions {
581
- mode: "dark" | "light";
582
- anchor?: number; // 为标题添加锚点 0:不渲染;1:渲染于标题前;2:渲染于标题后,默认 0
583
- customEmoji?: { [key: string]: string }; // 自定义 emoji,默认为 {}
584
- lang?: (keyof II18nLang); // 语言,默认为 'zh_CN'
585
- emojiPath?: string; // 表情图片路径
586
- hljs?: IHljs; // 参见 options.preview.hljs
587
- speech?: { // 对选中后的内容进行阅读
588
- enable?: boolean,
589
- };
590
- math?: IMath; // 数学公式渲染配置
591
- cdn?: string; // 自建 CDN 地址
592
- transform?(html: string): string; // 在渲染前进行的回调方法
593
- after?(); // 渲染完成后的回调
594
- lazyLoadImage?: string; // 设置为 Loading 图片地址后将启用图片的懒加载
595
- markdown?: options.preview.markdown;
596
- theme?: options.preview.theme;
597
- render?: options.preview.render;
598
- renderers?: ILuteRender; // 自定义渲染 https://ld246.com/article/1588412297062
599
- }
600
- ```
212
+ ### 图片尺寸语法(自定义扩展)
601
213
 
602
- * ⚠️ `method.min.js` 和 `index.min.js` 不可同时引入
603
-
604
- | | 说明 |
605
- | - | - |
606
- | previewImage(oldImgElement: HTMLImageElement, lang: keyof II18n = "zh_CN", theme = "classic") | 点击图片预览 |
607
- | mermaidRender(element: HTMLElement, cdn = options.cdn, theme = options.theme) | 流程图/时序图/甘特图 |
608
- | SMILESRender(element: HTMLElement, cdn = options.cdn, theme = options.theme) | 化学物质结构 |
609
- | markmapRender(element: HTMLElement, cdn = options.cdn) | markdown 思维导图 |
610
- | flowchartRender(element: HTMLElement, cdn = options.cdn) | flowchart 渲染 |
611
- | codeRender(element: HTMLElement, option?: IHljs) | 为 element 中的代码块添加复制按钮 |
612
- | chartRender(element: (HTMLElement \| Document) = document, cdn = options.cdn, theme = options.theme) | 图表渲染 |
613
- | mindmapRender(element: (HTMLElement \| Document) = document, cdn = options.cdn, theme = options.theme) | 脑图渲染 |
614
- | plantumlRender(element: (HTMLElement \| Document) = document, cdn = options.cdn) | plantuml 渲染 |
615
- | abcRender(element: (HTMLElement \| Document) = document, cdn = options.cdn) | 五线谱渲染 |
616
- | md2html(mdText: string, options?: IPreviewOptions): Promise\<string> | Markdown 文本转换为 HTML,该方法需使用[异步编程](https://ld246.com/article/1546828434083?r=Vanessa#toc_h3_1) |
617
- | preview(previewElement: HTMLDivElement, markdown: string, options?: IPreviewOptions) | 页面 Markdown 文章渲染 |
618
- | highlightRender(hljsOption?: IHljs, element?: HTMLElement \| Document, cdn = options.cdn) | 为 element 中的代码块进行高亮渲染 |
619
- | mediaRender(element: HTMLElement) | 为[特定链接](https://ld246.com/article/1589813914768)分别渲染为视频、音频、嵌入的 iframe |
620
- | mathRender(element: HTMLElement, options?: {cdn?: string, math?: IMath}) | 对数学公式进行渲染 |
621
- | speechRender(element: HTMLElement, lang?: (keyof II18nLang)) | 对选中的文字进行阅读 |
622
- | graphvizRender(element: HTMLElement, cdn?: string) | 对 graphviz 进行渲染 |
623
- | outlineRender(contentElement: HTMLElement, targetElement: Element) | 对大纲进行渲染 |
624
- | lazyLoadImageRender(element: (HTMLElement \| Document) = document) | 对启用懒加载的图片进行渲染 |
625
- | setCodeTheme(codeTheme: string, cdn = options.cdn) | 设置代码主题,codeTheme 参见 options.preview.hljs.style |
626
- | setContentTheme(contentTheme: string, path: string) | 设置内容主题,contentTheme 参见 options.preview.theme.list |
627
-
628
- ## 🏛️ 项目架构
629
-
630
- ### 一、架构概述
631
-
632
- Vditor 采用模块化架构,支持三种编辑模式:
633
-
634
- | 模式 | 说明 | 目录 |
635
- |------|------|------|
636
- | WYSIWYG | 所见即所得模式 | [src/ts/wysiwyg/](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/) |
637
- | IR | 即时渲染模式 | [src/ts/ir/](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/ir/) |
638
- | SV | 分屏预览模式 | [src/ts/sv/](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/sv/) |
639
-
640
- ### 二、核心目录结构
214
+ - 普通语法:`![alt](url)` 自动添加默认尺寸 300x200
215
+ - 带尺寸语法:`![alt](url =300x200)` → 使用指定尺寸
641
216
 
642
- ```
643
- src/
644
- ├── index.ts # 主入口,Vditor 类
645
- ├── method.ts # 静态工具方法
646
- ├── assets/ # 静态资源
647
- │ ├── less/ # 样式文件
648
- │ ├── images/ # 图片资源
649
- │ └── js/ # 第三方库 (highlight, katex, mermaid, lute 等)
650
- └── ts/ # TypeScript 源码
651
- ├── constants.ts # 常量定义
652
- ├── ir/ # IR 模式 (即时渲染模式)
653
- ├── sv/ # SV 模式 (分屏预览模式)
654
- ├── wysiwyg/ # WYSIWYG 模式 (所见即所得)
655
- ├── toolbar/ # 工具栏
656
- ├── markdown/ # Markdown 渲染相关
657
- ├── preview/ # 预览相关
658
- ├── hint/ # 提示补全
659
- ├── upload/ # 文件上传
660
- ├── undo/ # 撤销重做
661
- ├── util/ # 工具函数
662
- └── ui/ # UI 相关
663
- ```
217
+ ### 文档链接语法(自定义扩展)
664
218
 
665
- ### 三、WYSIWYG 模式核心文件
219
+ - 语法:`((1225096851397541888 "测试"))` → 渲染为带 id 的链接
666
220
 
667
- | 文件 | 功能 |
668
- |------|------|
669
- | [index.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/index.ts) | 主类,绑定事件(复制/剪切/粘贴/拖拽等) |
670
- | [input.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/input.ts) | 输入处理,调用 SpinVditorDOM 渲染 |
671
- | [renderDomByMd.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/renderDomByMd.ts) | Markdown 渲染 + **图片尺寸处理** |
672
- | [afterRenderEvent.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/afterRenderEvent.ts) | 渲染后事件处理 |
221
+ ---
673
222
 
674
- ### 四、图片尺寸功能(自定义语法)
223
+ ## 扩展功能模块
675
224
 
676
- #### 语法格式
677
- - 普通语法:`![alt](url)` → 自动添加默认尺寸 300x200
678
- - 带尺寸语法:`![alt](url =300x200)` → 使用指定尺寸
225
+ ### 1. 预览模块 (`src/ts/preview/`)
679
226
 
680
- #### 核心处理文件
227
+ - `Preview.ts`: 预览类
228
+ - `render.ts`: 渲染预览内容
229
+ - `theme.ts`: 预览主题切换
230
+ - 支持内容主题:ant-design, light, dark, wechat
681
231
 
682
- | 文件 | 功能 |
683
- |------|------|
684
- | [renderDomByMd.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/wysiwyg/renderDomByMd.ts) | **预处理**:`preprocessImageSize()` 在 Markdown 层面添加默认尺寸<br>**后处理**:`processImageSizeInDOM()` 转换文本为 `<img>` 标签 |
685
- | [imageResize.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/imageResize.ts) | **拖拽resize**:四角检测 (nw/ne/sw/se),无蓝色手柄,鼠标悬停变色 |
686
- | [getMarkdown.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/markdown/getMarkdown.ts) | **导出Markdown**:`processImageSizeInHTML()` 将 `<img>` 转回 `![alt](url =WxH)` 语法 |
232
+ ### 2. 提示补全模块 (`src/ts/hint/`)
687
233
 
688
- ### 五、工具函数模块 ([util/](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/))
234
+ - 表情自动补全
235
+ - @用户自动补全
236
+ - #话题自动补全
237
+ - 支持自定义扩展
689
238
 
690
- | 文件 | 功能 |
691
- |------|------|
692
- | [Options.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/Options.ts) | 配置选项合并 |
693
- | [selection.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/selection.ts) | 光标/选区操作 |
694
- | [fixBrowserBehavior.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/fixBrowserBehavior.ts) | 浏览器行为修复 |
695
- | [editorCommonEvent.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/editorCommonEvent.ts) | 编辑器通用事件 (复制/剪切/粘贴/拖拽等) |
696
- | [imageResize.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/imageResize.ts) | 图片拖拽调整尺寸 |
697
- | [processCode.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/processCode.ts) | 代码块渲染处理 |
698
- | [hasClosest.ts](file:///d:/workspaces/codeProjects/yl-vditor/src/ts/util/hasClosest.ts) | DOM 节点查找 |
239
+ ### 3. 文件上传模块 (`src/ts/upload/`)
699
240
 
700
- ### 六、渲染流程(WYSIWYG 模式)
241
+ - 拖拽上传
242
+ - 粘贴上传
243
+ - 实时进度
244
+ - CORS 跨域
245
+ - 支持自定义上传处理
701
246
 
702
- ```
703
- 用户输入 → input.ts → SpinVditorDOM(html) → processImageSizeInDOM() → afterRenderEvent()
704
-
705
- preprocessImageSize() 在 Markdown 层面添加默认尺寸(初始化时)
706
- ```
247
+ ### 4. 撤销重做模块 (`src/ts/undo/`)
707
248
 
708
- ## 🏗 开发文档
249
+ - 实时保存历史栈
250
+ - 支持撤销
251
+ - 支持重做
709
252
 
710
- ### 原理相关
253
+ ### 5. 大纲模块 (`src/ts/outline/`)
711
254
 
712
- * [关于所见即所得 Markdown 编辑器的讨论](https://ld246.com/article/1579414663700)
713
- * [Vditor 实现 Markdown 所见即所得](https://ld246.com/article/1577370404903)
714
- * [Lute 一款对中文语境优化的 Markdown 引擎,支持 Go 和 JavaScript](https://ld246.com/article/1567047822949)
255
+ - 目录生成
256
+ - 跳转导航
715
257
 
716
- ### 环境
258
+ ### 6. 评论模块 (`src/ts/comment/`)
717
259
 
718
- 1. 安装 [node](https://nodejs.org/) LTS 版本
719
- 2. [下载](https://github.com/Vanessa219/vditor/archive/master.zip)最新代码并解压
720
- 3. 根目录运行 `npm install`
721
- 4. `npm run start` 启动本地服务器,打开 http://localhost:9000
722
- 5. 修改代码
723
- 6. `npm run build` 打包代码到 dist 目录
260
+ - WYSIWYG 模式支持
261
+ - 高亮评论
262
+ - 删除评论
263
+ - 滚动定位
724
264
 
725
- ### CDN 切换
265
+ ### 7. 调整大小模块 (`src/ts/resize/`)
726
266
 
727
- 由于使用了按需加载的机制,默认 CDN 为 [https://unpkg.com/vditor](https://unpkg.com/vditor)@版本号
267
+ - 编辑器高度拖拽调整
728
268
 
729
- 如果代码有修改或需要使用自建 CDN 的话,可按以下步骤进行操作:
269
+ ---
730
270
 
731
- * 初始化时,需对 `options` 及 `IPreviewOptions` 中的 `cdn`,`emojiPath`, `themes` 进行配置
732
- * `highlightRender`,`mathRender`,`abcRender`,`chartRender`,`mermaidRender`,`SMILESRender`,`markmapRender`,`flowchartRender`,`mindmapRender`,`plantumlRender`,`graphvizRender`,`setCodeTheme`,`setContentTheme` 方法中需添加 cdn 参数
733
- * 将 build 成功的 dist 目录或 [jsDelivr](https://www.jsdelivr.com/package/npm/vditor?path=dist) 中的 dist 目录拷贝至正确的位置
271
+ ## 开发环境
734
272
 
735
- ### 升级
273
+ ### 安装依赖
736
274
 
737
- 版本升级时请**仔细阅读** [CHANGELOG](https://github.com/Vanessa219/vditor/blob/master/CHANGELOG.md) 中的**升级**部分
275
+ ```bash
276
+ npm install
277
+ ```
738
278
 
739
- ## Ⓜ️ Markdown 使用指南
279
+ ### 启动开发服务器
740
280
 
741
- * [基础语法](https://ld246.com/article/1583129520165)
742
- * [扩展语法](https://ld246.com/article/1583305480675)
743
- * [速查手册](https://ld246.com/article/1583308420519)
281
+ ```bash
282
+ npm run start
283
+ ```
744
284
 
745
- ## 🏘️ 社区
285
+ 访问 http://localhost:9000
746
286
 
747
- * [官网](https://b3log.org/vditor)
748
- * [讨论区](https://ld246.com/tag/vditor)
749
- * [报告问题](https://github.com/Vanessa219/vditor/issues/new)
287
+ ### 打包构建
750
288
 
751
- ## 📄 授权
289
+ ```bash
290
+ npm run build
291
+ ```
752
292
 
753
- Vditor 使用 [MIT](https://opensource.org/licenses/MIT) 开源协议。
293
+ 输出到 `dist/` 目录
754
294
 
755
- ## 🙏 鸣谢
295
+ ### 常用命令
756
296
 
757
- * [Lute](https://github.com/88250/lute):🎼 一款结构化的 Markdown 引擎,支持 Go 和 JavaScript
758
- * [highlight.js](https://github.com/highlightjs/highlight.js):JavaScript syntax highlighter
759
- * [mermaid](https://github.com/knsv/mermaid):Generation of diagram and flowchart from text in a similar manner as Markdown
760
- * [incubator-echarts](https://github.com/apache/incubator-echarts):A powerful, interactive charting and visualization library for browser
761
- * [abcjs](https://github.com/paulrosen/abcjs):JavaScript library for rendering standard music notation in a browser
297
+ - `npm run build`: 生产构建
298
+ - `npm run start`: 启动开发服务器
299
+ - `npm run test`: 运行测试
762
300
 
763
- ## 📽️ 历史
301
+ ---
764
302
 
765
- 我们在开发 [Sym](https://github.com/88250/symphony) 的初期是直接使用 WYSIWYG 富文本编辑器的。那时候基于 HTML 的编辑器非常流行,项目中引用起来也很方便,也符合用户当时的使用习惯。
303
+ ## 核心技术栈
766
304
 
767
- 后来,Markdown 的崛起逐步改变了大家的排版方式。再加上我们其他几个项目都是面向程序员用户的,所以迁移到 md 上也是大势所趋。我们选择了 [CodeMirror](https://github.com/codemirror/CodeMirror),这是一款优秀的编辑器,它对开发者提供了丰富的编程接口,对各种浏览器的兼容性也比较好。
305
+ - TypeScript
306
+ - Lute (Markdown 解析引擎)
307
+ - highlight.js (代码高亮)
308
+ - KaTeX/MathJax (数学公式)
309
+ - Mermaid (流程图)
310
+ - ECharts (图表)
311
+ - abcjs (五线谱)
768
312
 
769
- 再后来,随着我们项目业务需求方面的沉淀,使用 CodeMirror 有时候会感到比较“笨重”。比如要实现 @自动完成用户名列表、插入 Emoji、上传文件等就需要比较深入的二次开发,而这些业务需求恰恰是很多项目场景共有且必备的。
313
+ ---
770
314
 
771
- 终于,我们决定开始在 Sym 中自己实现编辑器。随着几个版本的迭代,Sym 的编辑器也日趋成熟。在我们运营的社区[链滴](https://ld246.com)上陆续有人问我们是否能将编辑器单独抽离出来提供给大家使用。与此同时,我们的前端主程 [V](https://ld246.com/member/Vanessa) 同学对于维护分散在各个项目中的编辑器也感到有点力不从心,外加对 TypeScript 的好感,所以就决定使用 ts 来实现一个全新的浏览器端 md 编辑器。
315
+ ## 授权
772
316
 
773
- 于是,Vditor 就这样诞生了。
317
+ MIT